home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / x / volume0 / awm / part09 < prev    next >
Encoding:
Internet Message Format  |  1988-08-10  |  51.0 KB

  1. Path: uunet!wyse!mikew
  2. From: mikew@wyse.wyse.com (Mike Wexler)
  3. Newsgroups: comp.sources.x
  4. Subject: v00i009:  Ardent Window Manager, Part09/13
  5. Message-ID: <1633@wyse.wyse.com>
  6. Date: 10 Aug 88 21:59:14 GMT
  7. Sender: news@wyse.wyse.com
  8. Lines: 1798
  9. Approved: mikew@wyse.com
  10.  
  11. Submitted-by: unido!pcsbsd!jkh (Jordan Hubbard)
  12. Posting-number: Volume 0, Issue 9
  13. Archive-name: awm/part09
  14.  
  15. [NOTE: Jordan Hubbard has moved.  The first postings listed his 
  16. address as jkh@ardent.  His current address is unido!pcsbst!jkh]
  17.  
  18. #! /bin/sh
  19. # This is a shell archive.  Remove anything before this line, then unpack
  20. # it by saving it into a file and typing "sh file".  To overwrite existing
  21. # files, type "sh file -c".  You can also feed this as standard input via
  22. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  23. # will see the following message at the end:
  24. #        "End of archive 9 (of 13)."
  25. # Contents:  awm/GetButton.c awm/menus/track_menu.c
  26. # Wrapped by mikew@wyse on Mon Aug  8 12:01:47 1988
  27. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  28. if test -f awm/GetButton.c -a "${1}" != "-c" ; then 
  29.   echo shar: Will not over-write existing file \"awm/GetButton.c\"
  30. else
  31. echo shar: Extracting \"awm/GetButton.c\" \(21347 characters\)
  32. sed "s/^X//" >awm/GetButton.c <<'END_OF_awm/GetButton.c'
  33. X#ident   "%W% %G%"
  34. X
  35. X
  36. X
  37. X#ifndef lint
  38. Xstatic char *rcsid_GetButton_c = "$Header: GetButton.c,v 1.4 88/07/23 18:20:45 jkh Exp $";
  39. X#endif    lint
  40. X
  41. X#include "X11/copyright.h"
  42. X/*
  43. X *
  44. X * Copyright 1987, 1988 by Ardent Computer Corporation, Sunnyvale, Ca.
  45. X *
  46. X * Copyright 1987 by Jordan Hubbard.
  47. X *
  48. X *
  49. X *                         All Rights Reserved
  50. X *
  51. X * Permission to use, copy, modify, and distribute this software and its
  52. X * documentation for any purpose and without fee is hereby granted,
  53. X * provided that the above copyright notice appear in all copies and that
  54. X * both that copyright notice and this permission notice appear in
  55. X * supporting documentation, and that the name of Ardent Computer
  56. X * Corporation or Jordan Hubbard not be used in advertising or publicity
  57. X * pertaining to distribution of the software without specific, written
  58. X * prior permission.
  59. X *
  60. X */
  61. X
  62. X/*
  63. X * Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
  64. X *
  65. X *                         All Rights Reserved
  66. X *
  67. X * Permission to use, copy, modify, and distribute this software and its
  68. X * documentation for any purpose and without fee is hereby granted,
  69. X * provided that the above copyright notice appear in all copies and that
  70. X * both that copyright notice and this permission notice appear in
  71. X * supporting documentation, and that the name of Digital Equipment
  72. X * Corporation not be used in advertising or publicity pertaining to
  73. X * distribution of the software without specific, written prior permission.
  74. X *
  75. X *
  76. X * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
  77. X * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
  78. X * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
  79. X * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  80. X * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
  81. X * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
  82. X * SOFTWARE.
  83. X */
  84. X
  85. X
  86. X
  87. X/*
  88. X * MODIFICATION HISTORY
  89. X *
  90. X * 000 -- M. Gancarz, DEC Ultrix Engineering Group
  91. X * 001 -- L. Guarino Reid, DEC Ultrix Engineering Group, Western Software Lab
  92. X *      February 16, 1987
  93. X *      Add EnterWindow, LeaveWindow, and MouseMotion as recognized
  94. X *      awm buttons for awm menus. Add bug fixes to prevent mem faults
  95. X *      if icon_str is NULL.
  96. X * 002 -- L. Guarino Reid, DEC Ultrix Engineering Group
  97. X *      April 16, 1987
  98. X *      Convert to X11
  99. X * 003 -- J. Hubbard, U.C. Berkeley. Title/gadget box event handling.
  100. X *    December 3, 1987.
  101. X * 004 -- J.Hubbard, Ardent Computer. More conformance with ICCCM. Merge of
  102. X * changes from R2 uwm.
  103. X */
  104. X
  105. X#ifndef lint
  106. Xstatic char *sccsid = "@(#)GetButton.c    3.8    1/24/86";
  107. X#endif
  108. X/*
  109. X *    GetButton - This subroutine is used by the Ardent Window Manager (awm)
  110. X *    to acquire button events.  It waits for a button event to occur
  111. X *    and handles all event traffic in the interim.
  112. X *
  113. X *    File:        GetButton.c
  114. X */
  115. X
  116. X#include "awm.h"
  117. X#include "X11/Xutil.h"
  118. X
  119. Xextern XContext AwmContext;
  120. Xextern Window FocusWindow;
  121. X
  122. X#define ICONSTR    (icon_str ? icon_str : "")
  123. X/* Amount of padding between text in a title bar and the edge of the bar */
  124. X#define PAD    1
  125. X
  126. Xstatic Icon_modified = FALSE;
  127. X
  128. XBoolean GetButton(b_ev)
  129. XXEvent *b_ev;    /* Button event packet. */
  130. X{
  131. X#define STRLEN 50
  132. X     XKeyPressedEvent *kp_event;    /* Key pressed event. */
  133. X     char *icon_str;        /* Icon's name string. */
  134. X     register int icon_str_len;    /* Icon name string lenght.  */
  135. X     register int key_char;    /* Key press character code. */
  136. X     register int icon_x;    /* Icon window X coordinate. */
  137. X     register int icon_y;    /* Icon window Y coordinate. */
  138. X     register int icon_w;    /* Icon window width. */
  139. X     register int icon_h;    /* Icon window height. */    
  140. X     int status;            /* Routine call return status. */
  141. X     Window icon;        /* Icon window. */
  142. X     Window appl;        /* Application window. */
  143. X     XWindowAttributes win_info;    /* Icon window info structure. */
  144. X     char kbd_str[STRLEN];      /* Keyboard string. */
  145. X     int nbytes;                /* Keyboard string length. */
  146. X     int i;                     /* Iteration counter. */
  147. X     Window win;        /* scratch */
  148. X     AwmInfoPtr awi;
  149. X     
  150. X     Entry("GetButton")
  151. X  
  152. X     /*
  153. X      * Get next event from input queue and store it in the event packet
  154. X      * passed to GetButton.
  155. X      */
  156. X  
  157. X     XNextEvent(dpy, b_ev);
  158. X     /* print_event_info("mainloop", b_ev); /* debugging for event handling */
  159. X
  160. X     /*
  161. X      * The event occured on the root window, check for substructure
  162. X      * changes. Otherwise, it must be a mouse button event. 
  163. X      */
  164. X
  165. X     if (b_ev->xany.window == RootWindow(dpy, scr)) {
  166. X      switch (b_ev->xany.type) {
  167. X      case CreateNotify:
  168. X      case UnmapNotify:
  169. X      case ReparentNotify:
  170. X      case ConfigureNotify:
  171. X      case GravityNotify:
  172. X      case MapNotify:
  173. X      case CirculateNotify:
  174. X           Leave(FALSE)
  175. X            
  176. X      case MappingNotify:
  177. X           XRefreshKeyboardMapping(b_ev);
  178. X           Leave(FALSE)
  179. X
  180. X      case MapRequest: 
  181. X           CheckMap(b_ev->xmap.window);
  182. X           Leave(FALSE)
  183. X
  184. X      case ConfigureRequest: 
  185. X           Configure((XConfigureEvent *)b_ev);
  186. X           Leave(FALSE)
  187. X           
  188. X      case CirculateRequest: 
  189. X           Circulate((XCirculateEvent *)b_ev);
  190. X           Leave(FALSE)
  191. X           
  192. X      case DestroyNotify:
  193. X           RemoveIcon(b_ev->xdestroywindow.window);
  194. X           Leave(FALSE)
  195. X
  196. X      case FocusIn:
  197. X           if (b_ev->xfocus.detail == NotifyPointerRoot) {
  198. X            if (FocusSetByUser) {
  199. X             XSetInputFocus(dpy, PointerRoot, None,
  200. X                    CurrentTime);
  201. X             FocusSetByUser = FALSE;
  202. X             FocusWindow = RootWindow(dpy, scr);
  203. X            }
  204. X           }
  205. X           Leave(FALSE)
  206. X           
  207. X      case FocusOut:
  208. X           if (b_ev->xfocus.detail == NotifyPointerRoot) {
  209. X            if (FocusSetByUser == FALSE && !FocusSetByWM) {
  210. X             XSetInputFocus(dpy, PointerRoot, None,
  211. X                    CurrentTime);
  212. X             FocusWindow = RootWindow(dpy, scr);
  213. X            }
  214. X           }
  215. X           Leave(FALSE)
  216. X           
  217. X      case ButtonPress:
  218. X      case ButtonRelease:
  219. X           Leave(TRUE)
  220. X
  221. X      default: 
  222. X           Leave(FALSE) 
  223. X      }
  224. X     }
  225. X     
  226. X     /*
  227. X      * If the event type is EnterWindow, LeaveWindow, or MouseMoved,
  228. X      * we are processing a menu. 
  229. X      * If the event type is ButtonPress or ButtonRelease,
  230. X      * we have a button event.
  231. X      * If it's an expose, then we may have exposed a title bar.
  232. X      * If it's a Notify, we've probably frobbed a titled window.
  233. X      */
  234. X     
  235. X     switch (b_ev->type) {
  236. X      XEvent e_fake;
  237. X
  238. X     case MotionNotify: 
  239. X     case ButtonPress: 
  240. X     case ButtonRelease: 
  241. X      Leave(TRUE)
  242. X      break;
  243. X
  244. X     case FocusIn:
  245. X      if (!FocusSetByWM) {
  246. X           e_fake.xcrossing.type = FocusIn;
  247. X           e_fake.xcrossing.focus = TRUE;
  248. X           e_fake.xcrossing.window = b_ev->xcrossing.window;
  249. X           HandleFocusIn(&e_fake);
  250. X      }
  251. X      Leave(FALSE)
  252. X      break;
  253. X
  254. X     case FocusOut:
  255. X      if (!FocusSetByWM) {
  256. X           e_fake.xcrossing.type = FocusOut;
  257. X           e_fake.xcrossing.focus = TRUE;
  258. X           e_fake.xcrossing.window = b_ev->xcrossing.window;
  259. X           HandleFocusOut(&e_fake);
  260. X      }
  261. X      Leave(FALSE)
  262. X      break;
  263. X      
  264. X     case EnterNotify:
  265. X      HandleFocusIn(b_ev);
  266. X      Leave(FALSE)
  267. X
  268. X     case LeaveNotify: 
  269. X      HandleFocusOut(b_ev);
  270. X      Leave(FALSE)
  271. X
  272. X     case ConfigureRequest:
  273. X      Configure((XConfigureEvent *)b_ev);
  274. X      Leave(FALSE)
  275. X
  276. X     case MapRequest:
  277. X      CheckMap(b_ev->xmap.window);
  278. X      Leave(FALSE);
  279. X
  280. X     case MapNotify:
  281. X      win = b_ev->xmap.window;
  282. X          if (!(awi = GetAwmInfo(win)))
  283. X              Leave(FALSE)
  284. X      if (IsIcon(win, FALSE))
  285. X          Leave(FALSE)
  286. X          XMapWindow(dpy, awi->frame);
  287. X      XMapWindow(dpy, awi->client);
  288. X          Leave(FALSE)
  289. X      break;
  290. X      
  291. X     case UnmapNotify:
  292. X      win = b_ev->xunmap.window;
  293. X          if (!(awi = GetAwmInfo(win)))
  294. X              Leave(FALSE)
  295. X
  296. X      if (IsIcon(win, FALSE))
  297. X           Leave(FALSE)
  298. X       XUnmapWindow(dpy, awi->frame);
  299. X      Leave(FALSE)
  300. X      break;
  301. X
  302. X     case DestroyNotify:
  303. X      win = b_ev->xdestroywindow.window;
  304. X          if (!(awi = GetAwmInfo(win)))
  305. X              Leave(FALSE)
  306. X      if (win != awi->title) {
  307. X           /* remove any icon associated with this window */
  308. X           RemoveIcon(win);
  309. X           /* remove the frame/titlebar (if present) */
  310. X           NoDecorate(win, TRUE);
  311. X           /* punt the rest of the per-window info */
  312. X           XDeleteContext(dpy, awi->client, AwmContext);
  313. X           free(awi);
  314. X      }
  315. X          Leave(FALSE)
  316. X
  317. X     case PropertyNotify:
  318. X      win = b_ev->xproperty.window;
  319. X          if (!(awi = GetAwmInfo(win)))
  320. X               Leave(FALSE)
  321. X      switch(b_ev->xproperty.atom) {
  322. X
  323. X      case XA_WM_COMMAND:
  324. X      case XA_WM_HINTS:
  325. X      case XA_WM_CLIENT_MACHINE:
  326. X           break;
  327. X
  328. X      case XA_WM_ICON_NAME:
  329. X           /*
  330. X        * Icon was modified by type-in (I still think that's a
  331. X        * gross feature, but some people like it... sigh),
  332. X        * ignore this event.
  333. X        */
  334. X           if (Icon_modified == TRUE) {
  335. X            Icon_modified = FALSE;    /* reset */
  336. X            Leave(FALSE)
  337. X           }
  338. X           if (awi->icon && awi->own && awi->iconPixmap == IBackPixmap) {
  339. X            win = awi->icon;
  340. X            status = XGetWindowAttributes(dpy, win, &win_info);
  341. X            icon_str = GetIconName(awi->client);
  342. X            icon_str_len = icon_str ? strlen(icon_str) : 0;
  343. X            if (win_info.width != XTextWidth(IFontInfo, ICONSTR,
  344. X                             strlen(ICONSTR)) +
  345. X            (HIconPad << 1)) {
  346. X             XResizeWindow(dpy, win, 
  347. X                       XTextWidth(IFontInfo, ICONSTR,
  348. X                          strlen(ICONSTR)) +
  349. X                       (HIconPad << 1), IFontInfo->ascent +
  350. X                       IFontInfo->descent + (VIconPad << 1));
  351. X            }
  352. X            XClearWindow(dpy, win);
  353. X            if (icon_str_len != 0) {
  354. X             XDrawImageString(dpy, win, IconGC, HIconPad,
  355. X                      VIconPad+IFontInfo->ascent, icon_str,
  356. X                      icon_str_len);
  357. X             free(icon_str);
  358. X            }
  359. X           }
  360. X           break;
  361. X
  362. X      case XA_WM_ICON_SIZE:
  363. X           break;
  364. X
  365. X      case XA_WM_NAME:
  366. X           if (awi->title) {
  367. X            if (awi->name)
  368. X             free(awi->name);
  369. X            awi->name = (char *)GetTitleName(win);
  370. X            PaintTitle(win, (FocusWindow == awi->client));
  371. X           }
  372. X           break;
  373. X
  374. X      case XA_WM_NORMAL_HINTS:
  375. X      case XA_WM_SIZE_HINTS:
  376. X      case XA_WM_ZOOM_HINTS:
  377. X           break;
  378. X
  379. X      default:
  380. X           fprintf(stderr, "awm: Got unknown property %d\n",
  381. X               b_ev->xproperty.atom);
  382. X      }
  383. X      Leave(FALSE)
  384. X      break;
  385. X      
  386. X      
  387. X     case Expose:
  388. X      win = b_ev->xexpose.window;
  389. X          if (!(awi = GetAwmInfo(win))) /* probably a menu */
  390. X               Leave(FALSE)
  391. X      if (awi->title == win) {
  392. X           if (b_ev->xexpose.count == 0) {
  393. X            XEvent evt;
  394. X
  395. X            /* Eat up any previous exposes */
  396. X            while (XCheckTypedWindowEvent(dpy, awi->title, Expose,
  397. X                          &evt));
  398. X            PaintTitle(win, (FocusWindow == awi->client));
  399. X            if (awi->gadgets)
  400. X             PaintGadgets(win);
  401. X           }
  402. X           Leave(FALSE)
  403. X      }
  404. X      break;
  405. X      
  406. X     default:
  407. X      break;
  408. X     }
  409. X     
  410. X     /*
  411. X      * If we got this far, the event must be for an icon.
  412. X      */
  413. X     win = b_ev->xany.window;
  414. X     if (!(awi = GetAwmInfo(win)))
  415. X          Leave(FALSE)
  416. X     status = XGetWindowAttributes(dpy, win, &win_info);
  417. X     if (status == FAILURE)
  418. X      Leave(FALSE)
  419. X     
  420. X     if (b_ev->type == MapNotify || 
  421. X     b_ev->type == UnmapNotify ||
  422. X     b_ev->type == CreateNotify ||
  423. X     b_ev->type == ReparentNotify ||
  424. X     b_ev->type == GravityNotify ||
  425. X     b_ev->type == CirculateNotify ||
  426. X     b_ev->type == ConfigureNotify)
  427. X      Leave(FALSE)
  428. X     
  429. X     /*
  430. X      * Initialize the icon position variables.
  431. X      */
  432. X     icon_x = win_info.x;
  433. X     icon_y = win_info.y;
  434. X     
  435. X     /*
  436. X      * Get the name of the window associated with the icon and
  437. X      * determine its length.
  438. X      */
  439. X     if (!awi->icon)
  440. X      Leave(FALSE)
  441. X     /*
  442. X      * If we don't own it, or it's got a background pixmap, we don't have
  443. X      * to repaint it.
  444. X      */
  445. X     if (!awi->own || (awi->iconPixmap != IBackPixmap))
  446. X      Leave(FALSE)
  447. X     icon = awi->icon;
  448. X     icon_str = GetIconName(awi->client);
  449. X     icon_str_len = icon_str ? strlen(icon_str) : 0;
  450. X     
  451. X     /*
  452. X      * If the event is a window exposure event and the icon's name string
  453. X      * is not of zero length, simply repaint the text in the icon window
  454. X      * and return FALSE.
  455. X      */
  456. X     if (b_ev->type == Expose && (!Freeze || Frozen == 0)) {
  457. X      if (win_info.width != XTextWidth(IFontInfo, ICONSTR,
  458. X                       strlen(ICONSTR))+(HIconPad << 1)) {
  459. X           XResizeWindow(dpy, icon, 
  460. X                 XTextWidth(IFontInfo, ICONSTR,
  461. X                    strlen(ICONSTR)) + (HIconPad << 1),
  462. X                 IFontInfo->ascent + IFontInfo->descent + 
  463. X                 (VIconPad << 1));
  464. X      }
  465. X      XClearWindow(dpy, icon);
  466. X      if (icon_str_len != 0) {
  467. X           XDrawImageString(dpy, icon,
  468. X                IconGC, HIconPad, VIconPad+IFontInfo->ascent,
  469. X                icon_str, icon_str_len);
  470. X           /*
  471. X        * Remember to free the icon name string.
  472. X        */
  473. X           free(icon_str);
  474. X      }
  475. X      Leave(FALSE)
  476. X     }
  477. X
  478. X#ifndef NO_ICON_TYPIN     
  479. X     /*
  480. X      * If we have gotten this far event can only be a key pressed event.
  481. X      */
  482. X     kp_event = (XKeyPressedEvent *) b_ev;
  483. X     
  484. X     /* 
  485. X      * We convert the key pressed event to ascii.
  486. X      */
  487. X     nbytes = XLookupString(kp_event, kbd_str, STRLEN, NULL);
  488. X     
  489. X     /*
  490. X      * If kbd_str is a "non-string", then don't do anything.
  491. X      */
  492. X     if (nbytes == 0) {
  493. X      if (icon_str)
  494. X           free(icon_str);
  495. X      Leave(FALSE)
  496. X     }
  497. X     for (i = 0; i < nbytes; i++) {
  498. X      key_char = kbd_str[i];
  499. X      /*
  500. X       * If the key was <DELETE>, then delete a character from the end of
  501. X       * the name, return FALSE.
  502. X       *
  503. X       * If the key was <CTRL-U>, then wipe out the entire window name
  504. X       * and return FALSE.
  505. X       *
  506. X       * All other ctrl keys are squashed and we return FALSE.
  507. X       *
  508. X       * All printable characters are appended to the window's name, which
  509. X       * may have to be grown to allow for the extra length.
  510. X       */
  511. X      if (key_char == '\177') {
  512. X           /*
  513. X        * <DELETE>
  514. X        */
  515. X           if (icon_str_len > 0) {
  516. X            icon_str_len--;
  517. X            icon_str[icon_str_len] = '\0';
  518. X           }
  519. X      }
  520. X      else if (key_char == '\025') {
  521. X           /*
  522. X        * <CTRL-U>
  523. X        */
  524. X           if (icon_str_len > 0) {
  525. X            icon_str_len = 0;
  526. X            icon_str[0] = '\0';
  527. X           }
  528. X      }
  529. X      else if (key_char < IFontInfo->min_char_or_byte2 ||
  530. X           key_char > IFontInfo->max_char_or_byte2) {
  531. X           /*
  532. X        * Any other random (non-printable) key; ignore it.
  533. X        */
  534. X           /* do nothing */ ;
  535. X               }
  536. X      else {
  537. X           /*
  538. X        * ASCII Alphanumerics.
  539. X        */
  540. X           if (icon_str == NULL)
  541. X            icon_str = (char *) malloc (icon_str_len + 2);
  542. X           else
  543. X            icon_str = (char *)realloc(icon_str, (icon_str_len + 2));
  544. X           if (icon_str == NULL) {
  545. X            errno = ENOMEM;
  546. X            Error("GetButton -> Realloc of window name string memory failed.");
  547. X           }
  548. X           icon_str[icon_str_len] = key_char;
  549. X           icon_str[icon_str_len + 1] = '\0';
  550. X           icon_str_len += 1;
  551. X      }
  552. X     }
  553. X     
  554. X     /*
  555. X      * Now that we have changed the size of the icon we have to reconfigure
  556. X      * it so that everything looks good.  Oh yes, don't forget to move the
  557. X      * mouse so that it stays in the window!
  558. X      */
  559. X     
  560. X     /*
  561. X      * Set the window name to the new string. Icon_modified is a kludge
  562. X      * that tells us to avoid the next PropertyNotify, as it's a result of
  563. X      * this call.
  564. X      */
  565. X     XSetIconName(dpy, awi->client, ICONSTR);
  566. X     Icon_modified = TRUE;
  567. X     /*
  568. X      * Determine the new icon window configuration.
  569. X      */
  570. X     icon_h = IFontInfo->ascent + IFontInfo->descent + (VIconPad << 1);
  571. X     icon_w = XTextWidth(IFontInfo, ICONSTR, strlen(ICONSTR));
  572. X     if (icon_w == 0) {
  573. X      icon_w = icon_h;
  574. X     }
  575. X     else {
  576. X      icon_w += (HIconPad << 1);
  577. X     }
  578. X     
  579. X     if (icon_x < 0) icon_x = 0;
  580. X     if (icon_y < 0) icon_y = 0;
  581. X     if (icon_x - 1 + icon_w + (IBorderWidth << 1) > ScreenWidth) {
  582. X      icon_x = ScreenWidth - icon_w - (IBorderWidth << 1) + 1;
  583. X     }
  584. X     if (icon_y - 1 + icon_h + (IBorderWidth << 1) > ScreenHeight) {
  585. X      icon_y = ScreenHeight - icon_h - (IBorderWidth << 1) + 1;
  586. X     }
  587. X     
  588. X     XMoveResizeWindow(dpy, icon, icon_x, icon_y, icon_w, icon_h);
  589. X     XWarpPointer(dpy, None, icon, 
  590. X          0, 0, 0, 0, (icon_w >> 1), (icon_h >> 1));
  591. X     
  592. X     /* 
  593. X      * Free the local storage and return FALSE.
  594. X      */
  595. X     if (icon_str)
  596. X      free(icon_str);
  597. X#endif
  598. X     Leave(FALSE)
  599. X}
  600. X
  601. XCheckMap(window)
  602. XWindow window;
  603. X{
  604. X     XWMHints *XGetWMHints();
  605. X     XWMHints *wmhints;
  606. X     int x, y, w, h;
  607. X     Window transient_for;
  608. X     Window jW;
  609. X     int border_width, j;
  610. X     Binding *bptr;
  611. X     AwmInfoPtr awi;
  612. X     unsigned long event_mask;
  613. X
  614. X     Entry("CheckMap")
  615. X
  616. X     /* if it's a transient window, we won't rubber-band
  617. X      * note that this call always sets transient_for.
  618. X      */
  619. X     if (!XGetTransientForHint( dpy, window, &transient_for )) {
  620. X      /*
  621. X       * Handle any registered grabs for this window. We do this here
  622. X       * because we may be about to make an icon out of this window
  623. X       * and we want to register any potential grabs on it before this
  624. X       * happens.
  625. X       */
  626. X      awi = GetAwmInfo(window);
  627. X      if (!awi) {
  628. X           for (bptr = Blist; bptr; bptr = bptr->next)
  629. X            if (bptr->context & WINDOW)
  630. X             Grab(bptr->mask, window);
  631. X           awi = RegisterWindow(window);
  632. X           Decorate(awi->client);
  633. X           event_mask = PropertyChangeMask | FocusChangeMask;
  634. X           if (!FrameFocus)
  635. X            event_mask |= (EnterWindowMask | LeaveWindowMask);
  636. X           XSelectInput(dpy, window, event_mask);
  637. X           SetBorderPixmaps(dpy, GrayPixmap);
  638. X      }
  639. X      if ((wmhints = XGetWMHints(dpy, window))) {
  640. X           if ((wmhints->flags & StateHint) && (awi->state & ST_WINDOW) &&
  641. X           (wmhints->initial_state == IconicState)) {
  642. X            /* window wants to be created as an icon. Leave size
  643. X               /* and position alone, create as icon. */
  644. X                         XFree(wmhints);
  645. X                         Iconify(window, 0, 0, 0, 0);
  646. X                         Leave_void
  647. X           }
  648. X           XFree(wmhints);
  649. X      }
  650. X     }
  651. X     else if ((awi = GetAwmInfo(window)) == NULL)
  652. X      awi = RegisterWindow(window);
  653. X     if (awi->state & ST_WINDOW) {
  654. X      if (!transient_for)
  655. X           PlaceWindow(window);
  656. X      XMapRaised(dpy, awi->frame);
  657. X      XMapWindow(dpy, awi->client);
  658. X      XSync(dpy, 0);
  659. X     }
  660. X     Leave_void
  661. X}
  662. X
  663. XConfigure(event)
  664. XXConfigureRequestEvent *event;
  665. X{
  666. X     XWindowChanges values;
  667. X     AwmInfoPtr awi;
  668. X     
  669. X     Entry("Configure")
  670. X
  671. X     values.x = event->x;
  672. X     values.y = event->y;
  673. X     values.width = event->width;
  674. X     values.height = event->height;
  675. X     values.border_width = event->border_width;
  676. X     values.stack_mode = event->detail;
  677. X     values.sibling = event->above;
  678. X
  679. X     ConfigureWindow(event->window, event->value_mask, &values);
  680. X     Leave_void
  681. X}
  682. X
  683. XCirculate(event)
  684. XXCirculateEvent *event;
  685. X{
  686. X     Entry("Circulate")
  687. X
  688. X     if (event->place == PlaceOnTop)
  689. X      XRaiseWindow(event->display, event->window);
  690. X     else
  691. X      XLowerWindow(event->display, event->window);
  692. X     Leave_void
  693. X}
  694. X
  695. XPlaceWindow(window)
  696. XWindow window;
  697. X{
  698. X     XSizeHints wsh;
  699. X     int x, y, w, h;
  700. X     Boolean configureit = False;
  701. X     XWindowChanges xwc;
  702. X     AwmInfoPtr awi;
  703. X     long flags;
  704. X
  705. X     wsh.flags = 0;
  706. X     flags = CWX | CWY | CWWidth | CWHeight;
  707. X     awi = GetAwmInfo(window);
  708. X     XGetSizeHints(dpy, window, &wsh, XA_WM_NORMAL_HINTS);
  709. X     CheckConsistency(&wsh);
  710. X     AskUser(dpy, scr, window, &x, &y, &w, &h, &wsh);
  711. X
  712. X     wsh.flags |= (USPosition | USSize);
  713. X     wsh.x = x;
  714. X     wsh.y = y;
  715. X     wsh.width = w;
  716. X     wsh.height = h;
  717. X     if (x < 0 || y < 0) {
  718. X      Window jW;
  719. X      int j, border_width;
  720. X
  721. X      XGetGeometry(dpy, window, &jW, &j, &j, &j, &j, &border_width, &j);
  722. X
  723. X      if (x < 0)
  724. X           x += DisplayWidth(dpy, scr) - w - (border_width<<1);
  725. X      if (y < 0)
  726. X           y += DisplayHeight(dpy, scr) - h - (border_width<<1);
  727. X     }
  728. X     if (awi->frame)
  729. X      XSetSizeHints(dpy, awi->frame, &wsh, XA_WM_NORMAL_HINTS);
  730. X     XSetSizeHints(dpy, awi->client, &wsh, XA_WM_NORMAL_HINTS);
  731. X#ifdef titan /* 5x4 alignment */
  732. X     x += (x % 5);
  733. X     y += (y % 4);
  734. X#endif
  735. X     xwc.x = x;
  736. X     xwc.y = y;
  737. X     xwc.height = h;
  738. X     xwc.width = w;
  739. X     ConfigureWindow(window, flags, &xwc);
  740. X     awi->state |= ST_PLACED;
  741. X}
  742. X
  743. XBoolean ConfigureWindow(w, mask, xwc)
  744. XWindow w;
  745. Xunsigned long mask;
  746. XXWindowChanges *xwc;
  747. X{
  748. X     XWindowAttributes xwa;
  749. X     AwmInfoPtr awi;
  750. X     int height, width, x, y;
  751. X     int bch = 0, bcv = 0;
  752. X     Entry("ConfigureWindow")
  753. X
  754. X     awi = GetAwmInfo(w);
  755. X     if (!awi)
  756. X          Leave(FALSE)
  757. X
  758. X     if (awi->attrs & AT_BORDER) {
  759. X      bcv = BContext + 1;
  760. X      bch = bcv * 2;
  761. X     }
  762. X
  763. X     height = xwc->height;
  764. X     width = xwc->width;
  765. X     x = y = 0;
  766. X     /* width */
  767. X     xwc->width += bch;
  768. X     if (awi->title)
  769. X      XResizeWindow(dpy, awi->title, xwc->width, titleHeight);
  770. X     /* height */
  771. X     if (awi->attrs & AT_TITLE) {
  772. X      y = titleHeight + 2;
  773. X      xwc->height += y;
  774. X     }
  775. X     if (awi->attrs & AT_BORDER) {
  776. X      if (!(awi->attrs & AT_TITLE)) {
  777. X           xwc->height += (bcv * 2);
  778. X           y = bcv;
  779. X      }
  780. X      else
  781. X           xwc->height += bcv;
  782. X      xwc->x -= (BContext + (awi->border_width ? awi->border_width : 1));
  783. X      x = BContext;
  784. X     }
  785. X     if (PushDown == FALSE) {
  786. X      if (awi->attrs & AT_TITLE)
  787. X           xwc->y -= (titleHeight + 2);
  788. X      else if (awi->attrs & AT_BORDER)
  789. X           xwc->y -= (BContext + (awi->border_width ?
  790. X                      awi->border_width : 1));
  791. X     }
  792. X     XConfigureWindow(dpy, awi->frame, mask, xwc);
  793. X     if (awi->gadgets)
  794. X      PutGadgets(w);
  795. X     xwc->width = width;
  796. X     xwc->height = height;
  797. X     xwc->x = x;
  798. X     xwc->y = y;
  799. X     XConfigureWindow(dpy, awi->client, mask, xwc);
  800. X     Leave(TRUE)
  801. X}
  802. X
  803. Xint
  804. XProcessRequests(box, num_vectors)
  805. XXSegment *box;
  806. Xint num_vectors;
  807. X{
  808. X    XEvent event;
  809. X
  810. X    XPeekEvent(dpy, &event);
  811. X    switch (event.type) {
  812. X
  813. X    case MapRequest:
  814. X    case ConfigureRequest:
  815. X    case CirculateRequest:
  816. X
  817. X        DrawBox();
  818. X        GetButton(&event);
  819. X        DrawBox();
  820. X        return TRUE;
  821. X    }
  822. X    return FALSE;
  823. X}
  824. END_OF_awm/GetButton.c
  825. if test 21347 -ne `wc -c <awm/GetButton.c`; then
  826.     echo shar: \"awm/GetButton.c\" unpacked with wrong size!
  827. fi
  828. # end of overwriting check
  829. fi
  830. if test -f awm/menus/track_menu.c -a "${1}" != "-c" ; then 
  831.   echo shar: Will not over-write existing file \"awm/menus/track_menu.c\"
  832. else
  833. echo shar: Extracting \"awm/menus/track_menu.c\" \(26723 characters\)
  834. sed "s/^X//" >awm/menus/track_menu.c <<'END_OF_awm/menus/track_menu.c'
  835. X#ident   "%W% %G%"
  836. X
  837. X#ifndef lint
  838. X     static char sccs_id[] = "@(#)track_menu.c    2.1 12/16/87  Siemens Corporate Research and Support, Inc.";
  839. X#endif
  840. X
  841. X
  842. X#include "X11/copyright.h"
  843. X
  844. X/* 
  845. X  RTL Menu Package Version 1.0
  846. X  by Joe Camaratta and Mike Berman, Siemens RTL, Princeton NJ, 1987
  847. X  
  848. X  track_menu.c: bring up menus and track the mouse
  849. X  */
  850. X
  851. X/*
  852. X *
  853. X * Copyright 1987, 1988 by Ardent Computer Corporation, Sunnyvale, Ca.
  854. X *
  855. X * Copyright 1987 by Jordan Hubbard.
  856. X *
  857. X *
  858. X *                         All Rights Reserved
  859. X *
  860. X * Permission to use, copy, modify, and distribute this software and its
  861. X * documentation for any purpose and without fee is hereby granted,
  862. X * provided that the above copyright notice appear in all copies and that
  863. X * both that copyright notice and this permission notice appear in
  864. X * supporting documentation, and that the name of Ardent Computer
  865. X * Corporation or Jordan Hubbard not be used in advertising or publicity
  866. X * pertaining to distribution of the software without specific, written
  867. X * prior permission.
  868. X *
  869. X */
  870. X
  871. X
  872. X/*
  873. X  
  874. X  Copyright 1987 by
  875. X  Siemens Corporate Research and Support, Inc., Princeton, New Jersey
  876. X  
  877. X  Permission to use, copy, modify, and distribute this software
  878. X  and its documentation for any purpose and without fee is
  879. X  hereby granted, provided that the above copyright notice
  880. X  appear in all copies and that both that copyright notice and
  881. X  this permission notice appear in supporting documentation, and
  882. X  that the name of Siemens not be used in advertising or
  883. X  publicity pertaining to distribution of the software without
  884. X  specific, written prior permission.  Siemens makes no
  885. X  representations about the suitability of this software for any
  886. X  purpose.  It is provided "as is" without express or implied
  887. X  warranty.
  888. X  
  889. X  */
  890. X
  891. X/*
  892. X * The menu package will break if you don't define this, but
  893. X * it's there in case you want to see just how and where the
  894. X * "eventstack" stuff is used and, if necessary, replace it.
  895. X */
  896. X#define SAVE_EVENTS
  897. X
  898. X
  899. X#include <stdio.h>
  900. X#include "X11/Xlib.h"
  901. X#include "X11/cursorfont.h"
  902. X#include "arrow_icon.h"
  903. X#include "null_icon.h"
  904. X#include "menu.h"
  905. X#include "menu.def.h"
  906. X#include "menu.ext.h"
  907. X#include "dbug.h"
  908. X#ifdef SAVE_EVENTS
  909. X#include "eventstack.h"
  910. X#endif
  911. X
  912. X#define MIN(x,y) (((x) <= (y))? x:y)
  913. X#define MAX(x,y) (((x) >= (y))? x:y)
  914. X
  915. X#define CLICK_TIME 290 /* in milliseconds */
  916. X
  917. X#define CursorLockMask (ButtonReleaseMask | ExposureMask)
  918. X
  919. X/* Event macros */
  920. X
  921. X#define EventGetXCoord(rep) ((rep).xmotion.x)
  922. X#define EventGetYCoord(rep) ((rep).xmotion.y)
  923. X#define EventType(rep) ((rep).type)
  924. X#define EventXWindow(rep) ((rep).xcrossing.window)
  925. X#define EventXTime(rep) ((rep).xcrossing.time)
  926. X#define EventXMode(rep) ((rep).xcrossing.mode)
  927. X#define EventXRootX(rep) ((rep).xcrossing.x_root)
  928. X#define EventXRootY(rep) ((rep).xcrossing.y_root)
  929. X#define EventXDetail(rep) ((rep).xcrossing.detail)
  930. X#define EventMWindow(rep) ((rep).xmotion.window)
  931. X#define EventMTime(rep) ((rep).xmotion.time)
  932. X#define EventButton(rep) ((rep).xbutton.button)
  933. X#define EventBWindow(rep) ((rep).xbutton.window)
  934. X#define EventBTime(rep) ((rep).xbutton.time)
  935. X#define EventEX(rep) ((rep).xexpose.x)
  936. X#define EventEY(rep) ((rep).xexpose.y)
  937. X#define EventEWidth(rep) ((rep).xexpose.width)
  938. X#define EventEHeight(rep) ((rep).xexpose.height)
  939. X#define PointerEvent(rep) \
  940. X     ((EventType(rep) == ButtonPress) || \
  941. X      (EventType(rep) == ButtonRelease) || \
  942. X      (EventType(rep) == MotionNotify) || \
  943. X      (EventType(rep) == EnterNotify) || \
  944. X      (EventType(rep) == LeaveNotify) || \
  945. X      (EventType(rep) == FocusIn) || \
  946. X      (EventType(rep) == FocusOut))
  947. X#define KeyEvent(rep) \
  948. X     ((EventType(rep) == KeyPress) || (EventType(rep) == KeyRelease))
  949. X/* Possible states for the state machine */
  950. Xtypedef enum
  951. X{
  952. X     Initial,      /* Inside a submenu, but not any item */
  953. X     CheckTrigger, /* Inside an item that has submenu, checking for pullright */
  954. X     Leaf,         /* Inside an item with no submenu */
  955. X     Exit,         /* Preparing to exit */
  956. X     LevelControl  /* Not in any submenu, waiting to enter something */
  957. X     } State;
  958. X
  959. XState InitialState(), CheckTriggerState(), LeafState(), LevelControlState(),
  960. X     GetItemState();
  961. Xbool EventNotSignificant(), PushSubmenu();
  962. X
  963. Xvoid OutputEvent(), GetNextSignificantEvent(), PopSubmenu(), 
  964. X     Highlight(), Unhighlight(), DisplayInitialMenus(), LockCursor(),
  965. X     TossExtraMoves(), UnlockCursor();
  966. X
  967. Xvoid ProcessExposeEvents();
  968. X
  969. Xvoid SaveTest();
  970. X
  971. XMenuItem *MenuGetItem();
  972. XMenu *MenuGetMenu();
  973. X
  974. X/* global state variables */
  975. X
  976. Xstatic MenuItem *current_item;
  977. Xstatic Menu *current_menu;
  978. Xstatic Window root_window;
  979. Xextern Display *dpy;
  980. Xextern int scr;
  981. Xstatic int level;            /* submenu level */
  982. Xstatic Time button_time;     /* time button press invoked */
  983. Xstatic Cursor wait_cursor = None;  /* empty cursor for lock state */
  984. Xstatic bool click_allowed;
  985. Xstatic bool lock_event_mask, unlock_event_mask;
  986. X
  987. Xextern int Autoselect;
  988. Xextern int MDelta;
  989. X
  990. X#ifdef SAVE_EVENTS
  991. Xstatic struct Ev_q *ev_save = 0;
  992. X#endif
  993. X
  994. X
  995. XMenuItem *TrackMenu(root_menu, root_x, root_y, 
  996. X            init_button, root, buttime)
  997. XMenu *root_menu;    /* Pointer to root menu requested to pop up   */
  998. Xint root_x, root_y; /* Position to start menu                     */
  999. Xint init_button;    /* The # of button used to pop up menu        */
  1000. XWindow root;        /* Window label for parent of menu            */
  1001. XTime buttime;       /* timestamp for button (or 0, if CLICK == 0) */
  1002. X{
  1003. X     State CurrentState = LevelControl;
  1004. X     XEvent Event_Reply;
  1005. X     int open_x;
  1006. X     bool selected = FALSE;
  1007. X     MenuItem *selected_item;
  1008. X     
  1009. X     Entry("TrackMenu")
  1010. X     
  1011. X     /* Initialize globals */
  1012. X     
  1013. X     button_time = buttime;
  1014. X     root_window = root;
  1015. X     level = 0;
  1016. X     current_menu = root_menu;
  1017. X     click_allowed = (TestOptionFlag(current_menu, clickokay))? TRUE : FALSE;
  1018. X     unlock_event_mask = (TestOptionFlag(current_menu, savebits))?
  1019. X      MenuEventMask : (MenuEventMask | ExposureMask);
  1020. X     lock_event_mask = (TestOptionFlag(current_menu, savebits))?
  1021. X      CursorLockMask : (CursorLockMask | ExposureMask);
  1022. X     
  1023. X     /* If not already done, set up the null cursor for lock state */
  1024. X     if (wait_cursor == None)
  1025. X     {
  1026. X      Pixmap wc_pixmap;
  1027. X      XColor fg, bg;
  1028. X      
  1029. X      wc_pixmap = XCreateBitmapFromData (dpy, root_window,
  1030. X                         null_icon_bits,
  1031. X                         null_icon_width, null_icon_height);
  1032. X      wait_cursor = XCreatePixmapCursor (dpy, wc_pixmap, wc_pixmap,
  1033. X                         &fg, &bg, 1, 1);
  1034. X     }
  1035. X     
  1036. X     
  1037. X     /* Block all other action by grabbing the server */
  1038. X     /*    XGrabServer (dpy); */
  1039. X     /* Don't think we need to grab the server... so for now, we won't */
  1040. X     
  1041. X#ifdef SAVE_EVENTS     
  1042. X     /* Get the present state, so it can be restored later */
  1043. X     /* Any events on the queue when we start get saved now, restored later */
  1044. X     SaveEvents (dpy, &ev_save, ~(unsigned long) ButtonReleaseMask);
  1045. X#endif
  1046. X     
  1047. X     LockCursor(root_window);
  1048. X     if (!(current_item =
  1049. X       Display_Menu(current_menu, NULLMENU, root_x, root_y)))
  1050. X     {
  1051. X      CurrentState = Exit;
  1052. X     }
  1053. X     /*
  1054. X      * First item is a label and autoselect is on, so we want
  1055. X      * to push on to the first "real" item.
  1056. X      */
  1057. X     if (ItemIsDeaf(current_item) && Autoselect)
  1058. X      current_item = current_item->nextItem;
  1059. X     LockCursor(ItemWindow(current_item));
  1060. X     open_x = root_x;
  1061. X     
  1062. X     /* Push to appropriate previous item, if any */
  1063. X     while (MenuHasInitialItem(current_menu) && (CurrentState != Exit))
  1064. X     {
  1065. X      current_item = GetInitialItem(current_menu);
  1066. X      ClearInitialItem(current_menu);
  1067. X      
  1068. X      /* if the initial item can't be selected, take first in list */
  1069. X      if (ItemIsNull(current_item) || ItemIsDisabled(current_item))
  1070. X      {
  1071. X           current_item = MenuItems(current_menu);
  1072. X           break;
  1073. X      }
  1074. X      else if (ItemIsLeaf(current_item)) /* then we're done */
  1075. X           break;
  1076. X      else
  1077. X      {
  1078. X           open_x += ItemGetArrowPosition(current_item);
  1079. X           if (!ItemIsDeaf(current_item))
  1080. X            Highlight(current_item);
  1081. X           TossExtraMoves(ItemWindow(current_item));
  1082. X           (void)PushSubmenu(open_x);
  1083. X      }
  1084. X     }
  1085. X     ProcessExposeEvents();
  1086. X     if (CurrentState != Exit)
  1087. X      CurrentState = (ItemIsLeaf(current_item)) ? Leaf : CheckTrigger;
  1088. X     if (!ItemIsDeaf(current_item))
  1089. X      Highlight(current_item);
  1090. X     XSync (dpy, 0);  /* get release click, if it's in queue */
  1091. X#ifdef SAVE_EVENTS
  1092. X     DisposeEvents(dpy, (PointerMotionMask | EnterWindowMask |
  1093. X             LeaveWindowMask | ExposureMask));
  1094. X#endif
  1095. X     LockCursor(ItemWindow(current_item));
  1096. X     PlacePointer(current_menu,current_item); 
  1097. X     UnlockCursor();
  1098. X          
  1099. X     /* State Machine */
  1100. X     
  1101. X     while (CurrentState != Exit)
  1102. X     {
  1103. X      GetNextSignificantEvent(&Event_Reply, init_button);
  1104. X      switch (CurrentState)
  1105. X      {
  1106. X      case LevelControl:
  1107. X           CurrentState = LevelControlState(Event_Reply);
  1108. X           break;
  1109. X      case Initial:
  1110. X           CurrentState = InitialState(Event_Reply);
  1111. X           break;
  1112. X      case CheckTrigger:
  1113. X           CurrentState = CheckTriggerState(Event_Reply);
  1114. X           break;
  1115. X      case Leaf:
  1116. X           CurrentState = LeafState(Event_Reply, &selected);
  1117. X           break;
  1118. X      default:
  1119. X           Retch("(RTLmenu) YOW! Unknown State! (%d)\n",
  1120. X             CurrentState);
  1121. X           CurrentState = Exit;
  1122. X           break;
  1123. X      }
  1124. X     }
  1125. X     /* Clean up and exit */
  1126. X     
  1127. X     selected_item = (selected)? current_item : NULLITEM;
  1128. X     while (level)
  1129. X     {
  1130. X      if (selected)
  1131. X           SetInitialItem(current_menu, current_item);
  1132. X      PopSubmenu();
  1133. X     }
  1134. X     if (selected)
  1135. X     {
  1136. X      SetInitialItem(current_menu, current_item);
  1137. X     }
  1138. X     
  1139. X     Undisplay_Menu(current_menu);
  1140. X     UnlockCursor();
  1141. X     XUngrabPointer(dpy, CurrentTime);
  1142. X     
  1143. X     /* Throw out any left over events from menu world */
  1144. X     /*    if (TestOptionFlag(current_menu, savebits)) {
  1145. X       XSync(dpy,1); 
  1146. X       XUngrabServer(dpy, CurrentTime);  add this if grab added! 
  1147. X       }
  1148. X       else
  1149. X       XSync(dpy,0);*/
  1150. X     
  1151. X     /* Push back any events that were lying around when menus started */
  1152. X     
  1153. X     XFlush(dpy);
  1154. X#ifdef SAVE_EVENTS
  1155. X     DisposeEvents(dpy, (PointerMotionMask | EnterWindowMask |
  1156. X             LeaveWindowMask | ExposureMask));
  1157. X     RestoreEvents(dpy, &ev_save);
  1158. X#endif
  1159. X     Leave(selected_item)
  1160. X}
  1161. X
  1162. X/* Used for debugging */
  1163. X
  1164. Xvoid OutputEvent(Event_Reply)
  1165. XXEvent Event_Reply;
  1166. X{
  1167. X     Entry("OutputEvent")
  1168. X
  1169. X     switch (EventType(Event_Reply))
  1170. X     {
  1171. X     case ButtonPress:
  1172. X     case ButtonRelease:
  1173. X      DBUG_5("RTLmenu","Button Press/Release, button %d on window %d at time %d\n",
  1174. X         EventButton(Event_Reply), EventBWindow(Event_Reply), 
  1175. X         EventBTime(Event_Reply));
  1176. X      break;
  1177. X     case MotionNotify:
  1178. X      DBUG_5("RTLmenu","Motion Notify on window %d at time %d, x=%d\n", 
  1179. X         EventMWindow(Event_Reply), EventMTime(Event_Reply),
  1180. X         EventGetXCoord(Event_Reply));
  1181. X      break;
  1182. X     case EnterNotify:
  1183. X      DBUG_4("RTLmenu","Enter Notify on window %d at time %d\n",
  1184. X         EventXWindow(Event_Reply), EventXTime(Event_Reply));
  1185. X      break;
  1186. X     case LeaveNotify:
  1187. X      DBUG_4("RTLmenu","Leave Notify on window %d at time %d\n",
  1188. X         EventXWindow(Event_Reply), EventXTime(Event_Reply));
  1189. X      break;
  1190. X     default:
  1191. X      DBUG_3("RTLmenu","Unexpected event type %d\n", EventType(Event_Reply));
  1192. X      break;
  1193. X     }
  1194. X     Leave_void
  1195. X}
  1196. X
  1197. Xstatic bool locked = FALSE;
  1198. X
  1199. X/* Lock the cursor: make it disappear, and ignore events it generates.  */
  1200. X/* Optionally, confine it to a single window.                           */
  1201. X/* (Using "None" for confine_window doesn't confine it.    )            */
  1202. Xvoid LockCursor(confine_window)
  1203. XWindow confine_window;
  1204. X{
  1205. X     int result;
  1206. X     
  1207. X     Entry("LockCursor")
  1208. X     
  1209. X     locked = TRUE;
  1210. X     result = XGrabPointer(dpy,
  1211. X               RootWindow(dpy, MenuScreen(current_menu)),
  1212. X               True, lock_event_mask, GrabModeSync, 
  1213. X               GrabModeAsync, confine_window,
  1214. X               wait_cursor, CurrentTime);
  1215. X     DBUG_3("RTLmenu","Lock Cursor grab = %d\n",result);
  1216. X     Leave_void
  1217. X}
  1218. X
  1219. X/* Unlock (and unconfine) the cursor.  If cursor lock is not set,    */
  1220. X/* this does nothing.                                                */
  1221. X
  1222. Xvoid UnlockCursor()
  1223. X{
  1224. X     int result;
  1225. X     
  1226. X     Entry("UnlockCursor")
  1227. X     
  1228. X     if (locked)
  1229. X     {
  1230. X      locked = FALSE;
  1231. X      result = XGrabPointer(dpy, 
  1232. X                RootWindow(dpy, MenuScreen(current_menu)),
  1233. X                True,  unlock_event_mask,
  1234. X                GrabModeAsync, GrabModeAsync, None,
  1235. X                MenuCursor(current_menu), CurrentTime);
  1236. X      DBUG_3("RTLmenu","Unlock Cursor grab = %d\n",result);        
  1237. X     }
  1238. X     Leave_void
  1239. X}
  1240. X
  1241. X/* Keep getting the X events, until finding one that may be interesting */
  1242. X/* to the operation of the state machine. */
  1243. X
  1244. Xvoid GetNextSignificantEvent(Event_Reply,init_button)
  1245. XXEvent *Event_Reply;
  1246. Xint init_button;        /* the button that initiated the menu */
  1247. X{
  1248. X     XEvent Next_Event_Reply;
  1249. X     bool InsignificantEvent = True;
  1250. X     
  1251. X     Entry("GetNextSignificantEvent")
  1252. X     
  1253. X     /* Loop as long as any of a number of "insignificant" events */
  1254. X     /* are found; when the event no longer matches one of the tests, */
  1255. X     /* it is assumed to be "significant" and returned.*/
  1256. X     do
  1257. X     {
  1258. X      XNextEvent(dpy, Event_Reply);
  1259. X      DBUG_EXECUTE("RTLmenu", OutputEvent(*Event_Reply));
  1260. X      
  1261. X      /* If this event is an "enter", check whether there is a   */
  1262. X      /* "leave" for the same window already in the queue,       */
  1263. X      /* immediately following it; if so, throw them both out    */
  1264. X      /* and get the next event                                  */
  1265. X      /* NOTE: might try to look further ahead, but this is      */
  1266. X      /* tricky because other events might intervene.            */
  1267. X      
  1268. X      if ((EventType(*Event_Reply) == EnterNotify) &&
  1269. X          (EventXMode(*Event_Reply) == NotifyNormal) &&
  1270. X          (QLength(dpy) > 0) &&
  1271. X          (MenuGetMenu(current_menu, EventXWindow(*Event_Reply))
  1272. X           != current_menu))
  1273. X      {
  1274. X           XPeekEvent(dpy, &Next_Event_Reply);
  1275. X           if ((EventType(Next_Event_Reply) == LeaveNotify) &&
  1276. X           (EventXMode(Next_Event_Reply) == NotifyNormal) &&
  1277. X           (EventXWindow(Next_Event_Reply) == EventXWindow(*Event_Reply)))
  1278. X           {
  1279. X            DBUG_2("RTLmenu","TOSS: Enter/leave pair.\n");
  1280. X            XNextEvent(dpy, Event_Reply);
  1281. X            XNextEvent(dpy, Event_Reply);
  1282. X           }
  1283. X      }
  1284. X#ifdef SAVE_EVENTS
  1285. X      if (EventNotSignificant(*Event_Reply, init_button))
  1286. X      {
  1287. X           if (!(PointerEvent(*Event_Reply) || KeyEvent(*Event_Reply)
  1288. X             || EventType(*Event_Reply) == Expose))
  1289. X           {
  1290. X            /* might be significant elsewhere -- save it for later */
  1291. X            AddEventToStore(&ev_save, *Event_Reply);
  1292. X           }
  1293. X      }
  1294. X      else
  1295. X#else
  1296. X           if (!EventNotSignificant(*Event_Reply, init_button))
  1297. X#endif
  1298. X            InsignificantEvent = FALSE;
  1299. X     }
  1300. X     while (InsignificantEvent);
  1301. X     
  1302. X     DBUG_2("RTLmenu","--->");
  1303. X     Leave_void
  1304. X}
  1305. X
  1306. X/* Check whether the event matches one of the events considered */
  1307. X/* "not significant".*/
  1308. Xbool EventNotSignificant(Event_Reply, init_button)
  1309. XXEvent Event_Reply;
  1310. Xint init_button;
  1311. X{
  1312. X     Entry("EventNotSignificant")
  1313. X
  1314. X     /* Insignificant if not in following list */
  1315. X     Leave(!((EventType(Event_Reply) == ButtonRelease) ||
  1316. X           (EventType(Event_Reply) == ButtonPress) ||
  1317. X           (EventType(Event_Reply) == MotionNotify) ||
  1318. X           (EventType(Event_Reply) == EnterNotify) ||
  1319. X           (EventType(Event_Reply) == Expose) ||
  1320. X           (EventType(Event_Reply) == LeaveNotify))
  1321. X         ||
  1322. X         /* Insignificant if leave or enter is not "Normal"  */
  1323. X         (((EventType(Event_Reply) == LeaveNotify) ||
  1324. X           (EventType(Event_Reply) == EnterNotify)) &&
  1325. X          (EventXMode(Event_Reply) != NotifyNormal))
  1326. X         ||
  1327. X         /* Insignificant if hit button other than initial one */
  1328. X         ((EventType(Event_Reply) == ButtonRelease) &&
  1329. X          (EventButton(Event_Reply) != init_button))
  1330. X         ||
  1331. X         /* Insignificant if tail end of a click -- and clicks allowed */
  1332. X         (click_allowed &&
  1333. X          (EventType(Event_Reply) == ButtonRelease) &&
  1334. X          (EventBTime(Event_Reply) - button_time < CLICK_TIME))
  1335. X         )
  1336. X}
  1337. X
  1338. XState LevelControlState(rep)
  1339. XXEvent rep;
  1340. X{
  1341. X     State next_state;
  1342. X     Menu *entered_menu;
  1343. X     MenuItem *entered_item;
  1344. X     
  1345. X     Entry("LevelControlState")
  1346. X     switch (EventType(rep))
  1347. X     {
  1348. X     case MotionNotify:
  1349. X     case LeaveNotify: 
  1350. X      next_state = LevelControl; /* loop back to this state */
  1351. X      break;
  1352. X     case EnterNotify:
  1353. X      /* Decide whether we've entered a menu window or item window */
  1354. X      entered_menu = MenuGetMenu(current_menu, EventXWindow(rep));
  1355. X      entered_item = MenuGetItem(current_menu,EventXWindow(rep));
  1356. X      
  1357. X      if ((MenuIsNull(entered_menu)) && (ItemIsNull(entered_item)))
  1358. X           /* Must be some other window; carry on */
  1359. X           next_state = LevelControl;
  1360. X      else if (!ItemIsNull(entered_item) &&
  1361. X           MenuIsDisplayed(ItemMenu(entered_item)))
  1362. X      {
  1363. X           /* we entered an item, but not a window. This should only happen */
  1364. X           /* when we stayed in the parent of the current submenu.  So,     */
  1365. X           /* Pop that submenu and get to the item.                         */
  1366. X           if (level)
  1367. X           {
  1368. X            LockCursor(ItemWindow(entered_item));
  1369. X            PopSubmenu();
  1370. X            ProcessExposeEvents();
  1371. X            UnlockCursor();
  1372. X            current_item = entered_item;
  1373. X            Highlight(current_item);
  1374. X            next_state = GetItemState(rep);
  1375. X           }
  1376. X           else /* I must be very confused... */
  1377. X           {
  1378. X            Retch("(RTLmenu) Tried to pop the root menu...\n");
  1379. X            next_state = Exit;
  1380. X           }
  1381. X      }
  1382. X      
  1383. X      else if (!MenuIsNull(entered_menu)&&
  1384. X           MenuIsDisplayed(entered_menu))
  1385. X      {
  1386. X           /* entered a menu that is displayed */
  1387. X           while ((current_menu != entered_menu) && level)
  1388. X            /* drop down the menu that was entered */
  1389. X            PopSubmenu();
  1390. X           ProcessExposeEvents();
  1391. X           UnlockCursor();
  1392. X           if (current_menu == entered_menu)
  1393. X            next_state = Initial;
  1394. X           else
  1395. X           {
  1396. X            next_state = Exit;
  1397. X            Retch("(RTLmenu) Couldn't find the menu I entered!!\n");
  1398. X           }
  1399. X      }
  1400. X      else 
  1401. X           next_state = LevelControl;
  1402. X      break;
  1403. X     case ButtonRelease:
  1404. X      next_state = Exit;
  1405. X      break;
  1406. X     default:
  1407. X      Retch("RTLmenu","YOW! Unexpected event! (%d)\n", rep.type);
  1408. X      next_state = Exit;
  1409. X      break;
  1410. X     }
  1411. X     Leave(next_state)
  1412. X}
  1413. X
  1414. X/* Figure out the status of the item we've just entered */
  1415. XState GetItemState(rep)
  1416. XXEvent rep;
  1417. X{
  1418. X     int open_x;
  1419. X     State next_state;
  1420. X     
  1421. X     Entry("GetItemState")
  1422. X     if (ItemIsNull(current_item))
  1423. X     {
  1424. X      Retch("(RTLmenu) null current item!");
  1425. X      next_state = Exit;
  1426. X     }
  1427. X     else if (MenuIsNull(current_menu))
  1428. X     {
  1429. X      Retch("(RTLmenu) null current menu!");
  1430. X      next_state = Exit;
  1431. X     }
  1432. X     else if (ItemIsLeaf(current_item))
  1433. X     {
  1434. X      if (MenuHasInitialItem(current_menu))
  1435. X           ClearInitialItem(current_menu);
  1436. X      next_state = Leaf;
  1437. X     }
  1438. X     else if (EventGetXCoord(rep) >= (int)(ItemGetArrowPosition(current_item) - 4))
  1439. X     {
  1440. X      /* entered item in "auto pop-up zone", i.e., over pull-right arrow. */
  1441. X      LockCursor(ItemWindow(current_item));
  1442. X      TossExtraMoves(ItemWindow(current_item));
  1443. X      if (PushSubmenu(EventXRootX(rep)))
  1444. X      {
  1445. X           LockCursor(ItemWindow(current_item));
  1446. X           PlacePointer(current_menu, current_item); 
  1447. X           next_state = Initial;
  1448. X           ProcessExposeEvents();
  1449. X      }
  1450. X      else
  1451. X           next_state = CheckTrigger;
  1452. X      UnlockCursor();
  1453. X     }
  1454. X     else if (MenuHasInitialItem(current_menu))
  1455. X     {
  1456. X      /* Entered menu has initial item -- move to it */
  1457. X      DBUG_2("RTLmenu","Pushing for initial item.");
  1458. X      current_item = GetInitialItem(current_menu);
  1459. X      open_x = ItemGetArrowPosition(current_item) +
  1460. X           EventXRootX(rep);        
  1461. X      ClearInitialItem(current_menu);
  1462. X      LockCursor(ItemWindow(current_item));
  1463. X      if (PushSubmenu(open_x))
  1464. X      {
  1465. X           ProcessExposeEvents();
  1466. X           LockCursor(ItemWindow(current_item));
  1467. X           PlacePointer(current_menu, current_item); 
  1468. X           next_state = Initial;
  1469. X      }
  1470. X      UnlockCursor();
  1471. X     }
  1472. X     else /* parent pull */
  1473. X      next_state = CheckTrigger;
  1474. X     Leave(next_state)
  1475. X}
  1476. X
  1477. XState InitialState( rep)
  1478. XXEvent rep;
  1479. X{
  1480. X     State next_state;
  1481. X     
  1482. X     Entry("Initial")
  1483. X     switch (EventType(rep))
  1484. X     {
  1485. X     case EnterNotify:
  1486. X      if (MenuIsNull(current_menu))
  1487. X      {
  1488. X           Retch("(RTLmenu) null current menu!?!?");
  1489. X           next_state = Exit;
  1490. X      }
  1491. X      else if (EventXDetail(rep) == NotifyInferior)
  1492. X           next_state = Initial;
  1493. X      else
  1494. X      {
  1495. X           current_item = MenuGetItem(current_menu, EventXWindow(rep));
  1496. X           if (ItemIsNull(current_item))
  1497. X           {
  1498. X            /* Retch("(RTLmenu) Window entered not an item!\n"); */
  1499. X            next_state = Exit;
  1500. X           }
  1501. X           else
  1502. X           {
  1503. X            Highlight(current_item);
  1504. X            next_state = GetItemState(rep);
  1505. X           }
  1506. X      }
  1507. X      break;
  1508. X     case LeaveNotify:
  1509. X      /* Decide whether we're actually leaving      */
  1510. X      /* this menu for another submenu or the root, */
  1511. X      /* or going into an item.                     */
  1512. X      next_state = (EventXDetail(rep) == NotifyInferior)?
  1513. X           Initial : LevelControl;
  1514. X      break;
  1515. X     case ButtonRelease:
  1516. X      next_state = Exit;
  1517. X      break;
  1518. X     case MotionNotify:
  1519. X      next_state = Initial;
  1520. X      break;
  1521. X     default:
  1522. X      Retch("(RTLmenu) YOW! Unexpected event! (%d)\n", rep.type);
  1523. X      next_state = Exit;
  1524. X      break;
  1525. X     }
  1526. X     Leave(next_state)
  1527. X}
  1528. X
  1529. X#define NotSet -1
  1530. X/* Look to see if pull-right is requested */
  1531. XState CheckTriggerState(rep)
  1532. XXEvent rep;
  1533. X{
  1534. X     State next_state = CheckTrigger;
  1535. X     static int Trigger = NotSet;
  1536. X     static int OldX, NewX, childX, button;
  1537. X     
  1538. X     Entry("CheckTrigger")
  1539. X     if (MenuIsNull(current_menu) || ItemIsNull(current_item))
  1540. X     {
  1541. X      Retch("(RTLmenu) Null menu or item...");
  1542. X      next_state = Exit;
  1543. X      goto exit;
  1544. X     }
  1545. X     if (Trigger == NotSet) /* set it */
  1546. X     {
  1547. X      Trigger = MIN(EventGetXCoord(rep) + MenuDelta(current_menu),
  1548. X            ItemGetArrowPosition(current_item));
  1549. X      NewX = NotSet;
  1550. X     }
  1551. X     switch (EventType(rep))
  1552. X     {
  1553. X     case LeaveNotify:
  1554. X      next_state = Initial;
  1555. X      Unhighlight(MenuGetItem(current_menu, EventXWindow(rep)));
  1556. X      Trigger = NotSet;
  1557. X      break;
  1558. X     case ButtonRelease:
  1559. X      next_state = Exit;
  1560. X      Trigger = NotSet;
  1561. X      break;
  1562. X      
  1563. X     case ButtonPress:
  1564. X      button = rep.xbutton.button;
  1565. X      while (TRUE) {
  1566. X           XNextEvent(dpy, &rep);
  1567. X           if (rep.type == ButtonRelease &&
  1568. X           rep.xbutton.button == button)
  1569. X            break;
  1570. X      }
  1571. X      next_state = CheckTrigger;
  1572. X      childX = TestOptionFlag(current_menu, fixedchild) ?
  1573. X           (MenuX(current_menu) + ItemGetArrowPosition(current_item)) :
  1574. X            EventXRootX(rep);
  1575. X      Trigger = NotSet;
  1576. X      if (PushSubmenu(childX))
  1577. X      {
  1578. X           next_state = LevelControl;
  1579. X           ProcessExposeEvents();
  1580. X           LockCursor(ItemWindow(current_item));
  1581. X           PlacePointer(current_menu, current_item);
  1582. X      }
  1583. X      UnlockCursor();
  1584. X      break;
  1585. X
  1586. X     case MotionNotify:
  1587. X      next_state = CheckTrigger;
  1588. X      OldX = NewX;
  1589. X      NewX = EventGetXCoord(rep);
  1590. X      if (NewX >= Trigger)
  1591. X      {
  1592. X           LockCursor(ItemWindow(current_item));
  1593. X           childX = TestOptionFlag(current_menu, fixedchild)?
  1594. X            (MenuX(current_menu) + ItemGetArrowPosition(current_item)):
  1595. X             EventXRootX(rep);
  1596. X           Trigger = NotSet;
  1597. X           if (PushSubmenu(childX))
  1598. X           {
  1599. X            next_state = LevelControl;
  1600. X            ProcessExposeEvents();
  1601. X            LockCursor(ItemWindow(current_item));
  1602. X            PlacePointer(current_menu, current_item); 
  1603. X           }
  1604. X           UnlockCursor();
  1605. X      }
  1606. X      else if (NewX < OldX) /* reverse motion */
  1607. X           Trigger = MIN(Trigger, NewX + MenuDelta(current_menu));
  1608. X      break;
  1609. X
  1610. X     default:
  1611. X      Retch("(RTLmenu) YOW! Unexpected event!\n");
  1612. X      next_state = Exit;
  1613. X      break;
  1614. X     }
  1615. X exit:
  1616. X     Leave(next_state)
  1617. X}
  1618. X
  1619. XState LeafState(rep,selected)
  1620. XXEvent rep;
  1621. Xbool *selected;
  1622. X{
  1623. X     State next_state;
  1624. X     
  1625. X     Entry("LeafState")
  1626. X     switch(EventType(rep))
  1627. X     {
  1628. X     case LeaveNotify:
  1629. X      Unhighlight(MenuGetItem(current_menu, EventXWindow(rep)));
  1630. X      next_state = Initial;
  1631. X      break;
  1632. X      
  1633. X     case ButtonRelease:
  1634. X      *selected = TRUE;
  1635. X      next_state = Exit;
  1636. X      break;
  1637. X     
  1638. X     case ButtonPress:
  1639. X     case EnterNotify:
  1640. X     case MotionNotify: /* if events set right, this never happens */
  1641. X      next_state = Leaf;
  1642. X      break;
  1643. X      
  1644. X     default:
  1645. X      Retch("(RTLMenu) YOW! Unexpected event! (%d)\n",
  1646. X        rep.type);
  1647. X      next_state = Exit;
  1648. X      break;
  1649. X     }
  1650. X     Leave(next_state)
  1651. X}
  1652. X
  1653. Xbool PushSubmenu(x)
  1654. Xint x;
  1655. X{
  1656. X     int y;
  1657. X     bool pushed;
  1658. X     MenuItem *new_current_item;
  1659. X     
  1660. X     Entry("PushSubmenu")
  1661. X
  1662. X     if (ItemIsNull(current_item))
  1663. X     {
  1664. X      Retch("(RTLMenu) Can't push from null item.\n");
  1665. X      pushed = FALSE;
  1666. X     }
  1667. X     else if (MenuIsNull(ItemSubmenu(current_item)))
  1668. X     {
  1669. X      Retch("(RTLmenu) Null submenu.\n");
  1670. X      pushed = FALSE;
  1671. X     }    
  1672. X     else if (ItemIsNull(MenuItems(ItemSubmenu(current_item))))
  1673. X      /* submenu has no items -- don't push, but not an error */
  1674. X      pushed = FALSE;
  1675. X     else
  1676. X     {
  1677. X      y =  ItemGetMiddleY(current_item);
  1678. X      ++level;
  1679. X      
  1680. X      if (new_current_item =
  1681. X          Display_Menu(ItemSubmenu(current_item), current_menu, x, y))
  1682. X      {
  1683. X           XFlush(dpy);
  1684. X           current_menu = ItemSubmenu(current_item);
  1685. X           current_item = new_current_item;
  1686. X           if (ItemIsDeaf(current_item) && Autoselect)
  1687. X            current_item = current_item->nextItem;
  1688. X           pushed = TRUE;
  1689. X      }
  1690. X      else
  1691. X      {
  1692. X           Retch("(RTLmenu) Display_Menu failed!\n");
  1693. X           pushed = FALSE;
  1694. X      }
  1695. X     }
  1696. X     Leave(pushed)
  1697. X}
  1698. X
  1699. Xvoid PopSubmenu()
  1700. X{
  1701. X     Menu *parent;
  1702. X     MenuItem *item;
  1703. X     
  1704. X     Entry("PopSubmenu")
  1705. X     --level;
  1706. X     parent = current_menu->parentMenu;
  1707. X     Undisplay_Menu(current_menu);
  1708. X     current_menu = parent;
  1709. X     if (!MenuIsNull(current_menu))
  1710. X     {
  1711. X      item = MenuItemHighlighted(current_menu);
  1712. X      if (!ItemIsNull(item))
  1713. X      {
  1714. X           current_item = item;
  1715. X      }
  1716. X     }
  1717. X     
  1718. X     Leave_void
  1719. X}
  1720. X
  1721. Xvoid Highlight(item)
  1722. XMenuItem *item;
  1723. X{
  1724. X     MenuItem *old_highlight;
  1725. X     
  1726. X     Entry("Highlight")
  1727. X     
  1728. X     old_highlight = MenuItemHighlighted(current_menu);
  1729. X     if ((item != old_highlight) && /* else, already highlighted */
  1730. X     (!ItemIsNull(item)))
  1731. X     {
  1732. X      if (!ItemIsNull(old_highlight) && !ItemIsDeaf(item))
  1733. X           Unhighlight(old_highlight); 
  1734. X      MenuInvert(ItemMenu(item), item);
  1735. X      SetHighlightItem(ItemMenu(item), item);
  1736. X     }
  1737. X     Leave_void
  1738. X}
  1739. X
  1740. Xvoid Unhighlight(item)
  1741. XMenuItem *item;
  1742. X{
  1743. X     Entry("Unhighlight")
  1744. X     if (!ItemIsNull(item))
  1745. X     {
  1746. X      if (MenuItemHighlighted(current_menu) == item)
  1747. X      {
  1748. X           MenuInvert(ItemMenu(item), item);
  1749. X           ResetHighlightItem(ItemMenu(item));
  1750. X      }
  1751. X     }
  1752. X     Leave_void
  1753. X}
  1754. X
  1755. Xvoid TossExtraMoves(window)
  1756. XWindow window;
  1757. X{
  1758. X     XEvent ev;
  1759. X     
  1760. X     Entry("TossExtraMoves")
  1761. X     /*    XSync(dpy,0);     /* make sure they're all on the queue      */
  1762. X     while (XCheckTypedWindowEvent(dpy, window, MotionNotify, &ev))
  1763. X      DBUG_2("RTLmenu","Tossing extra motion.\n");
  1764. X     Leave_void
  1765. X}
  1766. X
  1767. X
  1768. Xvoid ProcessExposeEvents()
  1769. X{
  1770. X     MenuItem *item;
  1771. X     XEvent ev;
  1772. X     
  1773. X     Entry("ProcessExposeEvents")
  1774. X
  1775. X     XSync(dpy,0);
  1776. X     while (XCheckTypedEvent(dpy, Expose, &ev))
  1777. X     {
  1778. X      item = MenuGetItem(current_menu, EventXWindow(ev));
  1779. X      if (!ItemIsNull(item))
  1780. X           Draw_Item(ItemMenu(item), item, EventEX(ev), EventEY(ev),
  1781. X             EventEWidth(ev), EventEHeight(ev));
  1782. X     }
  1783. X     Leave_void
  1784. X}
  1785. END_OF_awm/menus/track_menu.c
  1786. if test 26723 -ne `wc -c <awm/menus/track_menu.c`; then
  1787.     echo shar: \"awm/menus/track_menu.c\" unpacked with wrong size!
  1788. fi
  1789. # end of overwriting check
  1790. fi
  1791. echo shar: End of archive 9 \(of 13\).
  1792. cp /dev/null ark9isdone
  1793. MISSING=""
  1794. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 ; do
  1795.     if test ! -f ark${I}isdone ; then
  1796.     MISSING="${MISSING} ${I}"
  1797.     fi
  1798. done
  1799. if test "${MISSING}" = "" ; then
  1800.     echo You have unpacked all 13 archives.
  1801.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  1802. else
  1803.     echo You still need to unpack the following archives:
  1804.     echo "        " ${MISSING}
  1805. fi
  1806. ##  End of shell archive.
  1807. exit 0
  1808. Mike Wexler(wyse!mikew)    Phone: (408)433-1000 x1330
  1809.